import { Command } from './command'
import { Sudoku, SudokuCeilValue } from './sudoku'

export class SudokuGame {
  private sudoku: Sudoku
  private cmdList: Command[]
  private curIdx: number = -1
  // max step 50
  private capacity = 50

  static NewSudokuGame() {
    return new SudokuGame(Sudoku.NewDisplayState())
  }

  constructor(gameState: SudokuCeilValue[][]) {
    this.sudoku = new Sudoku(gameState)
    this.cmdList = []
  }

  execute(cmd: Command) {
    // execute command at once
    let isStateChanged = cmd.execute(this.sudoku)
    // if no state have changed, do nothing
    if (!isStateChanged) {
      return
    }
    // remove all after curIdx
    this.cmdList.splice(this.curIdx + 1)
    // shrink
    if (this.cmdList.length >= this.capacity) {
      this.cmdList.shift()
      this.curIdx--
    }
    this.cmdList.push(cmd)
    this.curIdx++
  }

  /**
   * Undo will undo one command
   */
  Undo() {
    // ignore if curIdx is -1
    if (this.curIdx < 0) {
      return
    }
    // undo command
    this.cmdList[this.curIdx].recover(this.sudoku)
    this.curIdx--
  }

  /**
   * Redo will redo one command
   */
  Redo() {
    if (this.curIdx >= this.cmdList.length - 1) {
      return
    }
    // redo command
    this.curIdx++
    this.cmdList[this.curIdx].execute(this.sudoku)
  }

  Clear() {
    this.sudoku.clearAnswerLayer()
  }

  SetPuzzle(puzzleStr: string) {
    this.sudoku.setPuzzleLayer(puzzleStr, 'black')
  }

  SetAnswer(answerStr: string) {
    this.sudoku.setAnswerLayer(answerStr)
  }

  SetConflictElem(elemStr: string) {
    this.sudoku.popColorLayer()
    this.sudoku.addColorLayer(elemStr, 'red')
  }

  ClearConflictElemDisplay(elemStr: string) {
    this.sudoku.popColorLayer()
  }

  get displayState() {
    return this.sudoku.displayState
  }

  get AnswerStr() {
    return this.sudoku.getAnswerLayerStr()
  }
}
